function Move(game) {
    this.game = game;
}

Move.prototype.getOponentValue = function(v) {
    if (v == 1) {
        return 2;
    }
    return 1;
}

Move.prototype.getNextMoveForValue = function(v) {
    var oponentValue = this.getOponentValue(v);

    var siblingValue = v;
    if (this.game.isFirstMoveForValue(v)) {
        siblingValue = oponentValue;
    }

    /**
     * generowanie populacji AI z ktorej zostanie wybrany najlepszy mozliwy ruch
     */
    var population = new Population();
    population.qty = 0; // disabled sorting into population
    population = this.getPopulationForValue(population, this.game, v, siblingValue);

    /**
     * czy najleszy ruch AI to ruch wygrywajacy
     */
    var items = population.items;
    var best = this.getBestItem(items);
    if (best.estimate >= E_WINNER) {
        best.info = 'AI population, Estimate::WINNER ';
        return best;
    }


    /**
     * weryfikacja osobnikow tej populacji
     */
    var populationTemp = new Population();
    populationTemp.qty = population.qty;

    for (var i in population.items) {
        var item = population.items[i];
        /**
         * 1. wygenerowanie ruchow przeciwnika na grze z osobnika
         * 2. jezeli osobnik w ktoryms ruchu wygrywa to usuwamy osobnika z populacji pierwotnej
         */
        populationTemp = this.getPopulationForValue(populationTemp, item.game, oponentValue, oponentValue);
    }

    items = populationTemp.items;
    var bestO = this.getBestItem(items);
    bestO.forValue = v;

    /**
     * czy najlepszy ruch przeciwnika jest wygrywajacy
     */
    if (bestO.estimate >= E_WINNER) {
        bestO.info = 'Oponent population, Estimate::WINNER ';
        return bestO;
    }

    /**
     * czy najlepszy ruch przeciwnika niebezpieczny
     */
    if (bestO.estimate >= E_WINNER_NEXT) {

        if (best.estimate >= E_WINNER_NEXT) {
            best.info = 'Oponent population, Estimate::WINNER_NEXT but MY move is first !';
            return best;
        }

        bestO.info = 'Oponent population, Estimate::WINNER_NEXT ';
        return bestO;
    }



    /**
     * brak sytuacji wygrywjacyh i niebezpiecznych
     * wykonujemy najlepszy ruch AI
     */
    best.info = 'algorythm ended';
    return best;
};


Move.prototype.getPopulationForValue = function(population, game, v, siblingValue) {
    var size = game.getSize();
    for (var x = 0; x < size; x++) {
        for (var y = 0; y < size; y++) {

            var value = game.getValue(x, y);

            if (value == 0 && (siblingValue === 0 || game.hasSiblings(x, y, siblingValue))) {
                var gameClone = new Game(game.game);
                gameClone.setValue(x, y, v);
                population.addItem(gameClone, x, y, v);
            }
        }
    }

    /**
     * jezeli w populacji nie ma osobnikow to proba wygenerowania nowej populacji
     * ale bez uwzgledniania rodzenstwa, czyli sibling = 0
     */
    if (population.items.length <= 0 && siblingValue !== 0) {
        population = this.getPopulationForValue(population, game, v, 0);
    }

    return population;
};

Move.prototype.getBestItem = function(items) {
    /**
     * wybranie najlepszych osobnikow
     */
    var res = [];
    var estimateMax = 0;
    for (var i in items) {
        var one = items[i];
        if (one.estimate === estimateMax) {
            // ta sama estymacja
            res.push(one);
        } else if (one.estimate > estimateMax) {
            // estymacja wieksza
            res = [];
            res.push(one);
            estimateMax = one.estimate;
        } else {
            // estymacja mniejsza
            continue;
        }
    }

    if (res.length <= 0) {
        var resultItem = new PopulationItem(null, null, null, null, 0);
        resultItem.info = 'Nie znaleziono zadnych osobnikow w populacji';
        return resultItem;
        //throw new Error('There is not population item in population set !');
    }

    function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    return res[getRandomInt(0, res.length - 1)];
};